/**
 * 聊天模块业务逻辑服务
 * 包含所有聊天相关的核心业务逻辑
 */

const { LhxUser, LhxVisit, LhxMessage, LhxChatPermission } = require('../db/lhx_models');
const { generateRoomId, parseRoomId, isUserInRoom } = require('../utils/lhx_room_helper');

class LhxChatService {
  
  /**
   * 验证患者是否可以与医生聊天
   * 基于就诊记录验证权限
   * @param {string} patientId - 患者ID
   * @param {string} doctorId - 医生ID
   * @returns {Promise<boolean>} 是否有聊天权限
   */
  async validateChatPermission(patientId, doctorId) {
    try {
      const visit = await LhxVisit.findOne({
        patientId: patientId,
        doctorId: doctorId,
        status: 'completed'
      });
      
      return !!visit;
    } catch (error) {
      console.error('验证聊天权限失败:', error);
      return false;
    }
  }

  /**
   * 获取患者可以聊天的医生列表
   * 基于患者的就诊记录
   * @param {string} patientId - 患者ID
   * @returns {Promise<Array>} 医生列表
   */
  async getPatientDoctorList(patientId) {
    try {
      // 使用聚合查询优化性能
      const result = await LhxVisit.aggregate([
        // 1. 匹配患者的已完成就诊记录
        { 
          $match: { 
            patientId: patientId, 
            status: 'completed' 
          }
        },
        
        // 2. 按医生分组，获取最后就诊时间
        { 
          $group: {
            _id: '$doctorId',
            lastVisitDate: { $max: '$visitDate' },
            department: { $last: '$department' },
            visitCount: { $sum: 1 }
          }
        },
        
        // 3. 关联医生信息
        { 
          $lookup: {
            from: 'lhxusers',
            localField: '_id',
            foreignField: 'userId',
            as: 'doctorInfo'
          }
        },
        
        // 4. 展开医生信息
        { $unwind: '$doctorInfo' },
        
        // 5. 筛选活跃医生
        { 
          $match: { 
            'doctorInfo.status': 'active',
            'doctorInfo.userType': 'doctor'
          }
        },
        
        // 6. 投影输出字段
        { 
          $project: {
            userId: '$doctorInfo.userId',
            name: '$doctorInfo.name',
            department: '$doctorInfo.department',
            avatar: '$doctorInfo.avatar',
            lastVisitDate: 1,
            visitCount: 1,
            // 生成房间ID
            roomId: { 
              $concat: [patientId, '_', '$doctorInfo.userId'] 
            }
          }
        },
        
        // 7. 按最后就诊时间排序
        { $sort: { lastVisitDate: -1 }}
      ]);
      
      return result;
    } catch (error) {
      console.error('获取患者医生列表失败:', error);
      throw new Error('获取医生列表失败');
    }
  }

  /**
   * 获取医生的聊天患者列表
   * 显示向该医生发起过聊天的患者
   * @param {string} doctorId - 医生ID
   * @returns {Promise<Array>} 患者聊天列表
   */
  async getDoctorChatList(doctorId) {
    try {
      // 使用聚合查询获取聊天列表
      const result = await LhxMessage.aggregate([
        // 1. 匹配包含该医生的房间
        { 
          $match: { 
            roomId: { $regex: `_${doctorId}$` }
          }
        },
        
        // 2. 按房间分组，获取最后消息和统计信息
        { 
          $group: {
            _id: '$roomId',
            lastMessage: { $last: '$$ROOT' },
            messageCount: { $sum: 1 },
            // 提取患者ID（房间ID的第一部分）
            patientId: { 
              $first: { 
                $arrayElemAt: [
                  { $split: ['$roomId', '_'] }, 
                  0
                ]
              }
            },
            // 计算未读消息数（简化版，假设医生未读）
            unreadCount: {
              $sum: {
                $cond: [
                  { $and: [
                    { $ne: ['$senderType', 'doctor'] },
                    { $ne: ['$status', 'read'] }
                  ]},
                  1,
                  0
                ]
              }
            }
          }
        },
        
        // 3. 关联患者信息
        { 
          $lookup: {
            from: 'lhxusers',
            localField: 'patientId',
            foreignField: 'userId',
            as: 'patientInfo'
          }
        },
        
        // 4. 展开患者信息
        { $unwind: '$patientInfo' },
        
        // 5. 筛选活跃患者
        { 
          $match: { 
            'patientInfo.status': 'active',
            'patientInfo.userType': 'patient'
          }
        },
        
        // 6. 投影输出字段
        { 
          $project: {
            roomId: '$_id',
            patient: {
              userId: '$patientInfo.userId',
              name: '$patientInfo.name',
              avatar: '$patientInfo.avatar'
            },
            lastMessage: {
              content: '$lastMessage.content',
              senderId: '$lastMessage.senderId',
              senderType: '$lastMessage.senderType',
              timestamp: '$lastMessage.timestamp',
              messageType: '$lastMessage.messageType'
            },
            messageCount: 1,
            unreadCount: 1
          }
        },
        
        // 7. 按最后消息时间排序
        { $sort: { 'lastMessage.timestamp': -1 }}
      ]);
      
      return result;
    } catch (error) {
      console.error('获取医生聊天列表失败:', error);
      throw new Error('获取聊天列表失败');
    }
  }

  /**
   * 获取聊天历史记录
   * @param {string} roomId - 房间ID
   * @param {number} page - 页码，默认1
   * @param {number} limit - 每页数量，默认500
   * @returns {Promise<Object>} 聊天记录和分页信息
   */
  async getChatHistory(roomId, page = 1, limit = 500) {
    try {
      const skip = (page - 1) * limit;
      
      // 获取消息总数
      const total = await LhxMessage.countDocuments({ roomId });
      
      // 获取分页消息（按时间倒序，最新的在前）
      const messages = await LhxMessage.find({ roomId })
        .sort({ timestamp: -1 })
        .skip(skip)
        .limit(limit)
        .lean();
      
      // 为了显示，需要反转数组（最老的在前）
      const reversedMessages = messages.reverse();
      
      return {
        messages: reversedMessages,
        pagination: {
          total,
          page,
          limit,
          totalPages: Math.ceil(total / limit),
          hasNext: page * limit < total,
          hasPrev: page > 1
        }
      };
    } catch (error) {
      console.error('获取聊天历史失败:', error);
      throw new Error('获取聊天记录失败');
    }
  }

  /**
   * 发送消息
   * @param {Object} messageData - 消息数据
   * @returns {Promise<Object>} 保存的消息对象
   */
  async sendMessage(messageData) {
    try {
      const { roomId, senderId, senderType, content, messageType = 'text', fileInfo = null } = messageData;
      
      // 验证房间和发送者权限
      if (!isUserInRoom(roomId, senderId, senderType)) {
        throw new Error('发送者无权在此房间发送消息');
      }
      
      // 创建消息对象
      const message = new LhxMessage({
        roomId,
        senderId,
        senderType,
        content,
        messageType,
        timestamp: new Date(),
        status: 'sent',
        ...(fileInfo && { fileInfo })
      });
      
      // 保存到数据库
      const savedMessage = await message.save();
      
      return savedMessage;
    } catch (error) {
      console.error('发送消息失败:', error);
      throw new Error('消息发送失败');
    }
  }

  /**
   * 创建聊天房间
   * 当患者第一次向医生发送消息时调用
   * @param {string} patientId - 患者ID
   * @param {string} doctorId - 医生ID
   * @param {string} firstMessage - 第一条消息内容
   * @returns {Promise<Object>} 房间信息和第一条消息
   */
  async createChatRoom(patientId, doctorId, firstMessage) {
    try {
      // 1. 验证聊天权限
      const hasPermission = await this.validateChatPermission(patientId, doctorId);
      if (!hasPermission) {
        throw new Error('无聊天权限，请先就诊');
      }
      
      // 2. 验证用户存在
      const [patient, doctor] = await Promise.all([
        LhxUser.findOne({ userId: patientId, userType: 'patient', status: 'active' }),
        LhxUser.findOne({ userId: doctorId, userType: 'doctor', status: 'active' })
      ]);
      
      if (!patient || !doctor) {
        throw new Error('用户不存在或已停用');
      }
      
      // 3. 生成房间ID
      const roomId = generateRoomId(patientId, doctorId);
      
      // 4. 检查房间是否已存在（通过查看是否有消息记录）
      const existingMessage = await LhxMessage.findOne({ roomId });
      if (existingMessage) {
        throw new Error('聊天房间已存在');
      }
      
      // 5. 发送第一条消息
      const message = await this.sendMessage({
        roomId,
        senderId: patientId,
        senderType: 'patient',
        content: firstMessage,
        messageType: 'text'
      });
      
      return {
        roomId,
        patient: {
          userId: patient.userId,
          name: patient.name,
          avatar: patient.avatar
        },
        doctor: {
          userId: doctor.userId,
          name: doctor.name,
          department: doctor.department,
          avatar: doctor.avatar
        },
        firstMessage: message
      };
    } catch (error) {
      console.error('创建聊天房间失败:', error);
      throw error;
    }
  }

  /**
   * 标记消息为已读
   * @param {string} roomId - 房间ID
   * @param {string} userId - 用户ID
   * @param {string} userType - 用户类型
   * @returns {Promise<number>} 标记的消息数量
   */
  async markMessagesAsRead(roomId, userId, userType) {
    try {
      // 标记不是自己发送的消息为已读
      const result = await LhxMessage.updateMany(
        {
          roomId,
          senderId: { $ne: userId },
          status: { $ne: 'read' }
        },
        { 
          $set: { 
            status: 'read',
            readAt: new Date()
          }
        }
      );
      
      return result.modifiedCount;
    } catch (error) {
      console.error('标记消息已读失败:', error);
      throw new Error('标记消息已读失败');
    }
  }

  /**
   * 获取用户信息
   * @param {string} userId - 用户ID
   * @returns {Promise<Object>} 用户信息
   */
  async getUserInfo(userId) {
    try {
      const user = await LhxUser.findOne({ 
        userId, 
        status: 'active' 
      }).lean();
      
      if (!user) {
        throw new Error('用户不存在');
      }
      
      return user;
    } catch (error) {
      console.error('获取用户信息失败:', error);
      throw error;
    }
  }

  /**
   * 获取患者的聊天医生列表
   * 显示患者已经与哪些医生聊过天
   * @param {string} patientId - 患者ID
   * @returns {Promise<Array>} 医生聊天列表
   */
  async getPatientChatList(patientId) {
    try {
      // 使用聚合查询获取聊天列表
      const result = await LhxMessage.aggregate([
        // 1. 匹配包含该患者的房间
        { 
          $match: { 
            roomId: { $regex: `^${patientId}_` }
          }
        },
        
        // 2. 按房间分组，获取最后消息和统计信息
        { 
          $group: {
            _id: '$roomId',
            lastMessage: { $last: '$$ROOT' },
            messageCount: { $sum: 1 },
            // 提取医生ID（房间ID的第二部分）
            doctorId: { 
              $first: { 
                $arrayElemAt: [
                  { $split: ['$roomId', '_'] }, 
                  1
                ]
              }
            },
            // 计算未读消息数（患者视角：医生发送的未读消息）
            unreadCount: {
              $sum: {
                $cond: [
                  { $and: [
                    { $ne: ['$senderType', 'patient'] },
                    { $ne: ['$status', 'read'] }
                  ]},
                  1,
                  0
                ]
              }
            }
          }
        },
        
        // 3. 关联医生信息
        { 
          $lookup: {
            from: 'lhxusers',
            localField: 'doctorId',
            foreignField: 'userId',
            as: 'doctorInfo'
          }
        },
        
        // 4. 展开医生信息
        { $unwind: '$doctorInfo' },
        
        // 5. 筛选活跃医生
        { 
          $match: { 
            'doctorInfo.status': 'active',
            'doctorInfo.userType': 'doctor'
          }
        },
        
        // 6. 投影输出字段
        { 
          $project: {
            roomId: '$_id',
            doctor: {
              userId: '$doctorInfo.userId',
              name: '$doctorInfo.name',
              department: '$doctorInfo.department',
              avatar: '$doctorInfo.avatar'
            },
            lastMessage: {
              content: '$lastMessage.content',
              senderId: '$lastMessage.senderId',
              senderType: '$lastMessage.senderType',
              timestamp: '$lastMessage.timestamp',
              messageType: '$lastMessage.messageType'
            },
            messageCount: 1,
            unreadCount: 1
          }
        },
        
        // 7. 按最后消息时间排序
        { $sort: { 'lastMessage.timestamp': -1 }}
      ]);
      
      return result;
    } catch (error) {
      console.error('获取患者聊天列表失败:', error);
      throw new Error('获取聊天列表失败');
    }
  }

  /**
   * 验证用户权限
   * @param {string} userId - 用户ID
   * @param {string} userType - 用户类型
   * @param {string} roomId - 房间ID（可选）
   * @returns {Promise<boolean>} 是否有权限
   */
  async validateUserPermission(userId, userType, roomId = null) {
    try {
      // 1. 验证用户存在且活跃
      const user = await LhxUser.findOne({ 
        userId, 
        userType, 
        status: 'active' 
      });
      
      if (!user) {
        return false;
      }
      
      // 2. 如果指定了房间，验证房间权限
      if (roomId) {
        return isUserInRoom(roomId, userId, userType);
      }
      
      return true;
    } catch (error) {
      console.error('验证用户权限失败:', error);
      return false;
    }
  }

  // ==================== 聊天权限管理方法 ====================

  /**
   * 检查患者是否可以与指定医生聊天
   */
  async canPatientChatWithDoctor(patientId, doctorId) {
    try {
      // 简化权限检查：默认允许所有聊天
      const [patient, doctor] = await Promise.all([
        LhxUser.findOne({ userId: patientId, userType: 'patient', status: 'active' }),
        LhxUser.findOne({ userId: doctorId, userType: 'doctor', status: 'active' })
      ]);

      if (!patient || !doctor) {
        return { canChat: false, reason: 'user_not_found' };
      }

      return { canChat: true, reason: 'default_policy' };
    } catch (error) {
      return { canChat: false, reason: 'system_error' };
    }
  }

  /**
   * 获取患者可以聊天的医生列表
   */
  async getAvailableDoctorsForPatient(patientId) {
    try {
      // 获取所有活跃医生
      const doctors = await LhxUser.find({
        userType: 'doctor',
        status: 'active'
      }).lean();

      const availableDoctors = [];
      
      for (const doctor of doctors) {
        // 检查是否已有聊天记录
        const roomId = generateRoomId(patientId, doctor.userId);
        const hasExistingChat = await LhxMessage.findOne({ roomId });

        availableDoctors.push({
          userId: doctor.userId,
          name: doctor.name,
          department: doctor.department,
          avatar: doctor.avatar,
          hasExistingChat: !!hasExistingChat,
          roomId: hasExistingChat ? roomId : null
        });
      }

      return availableDoctors;
    } catch (error) {
      throw new Error('获取医生列表失败');
    }
  }



  /**
   * 患者发起新聊天
   * @param {string} patientId - 患者ID
   * @param {string} doctorId - 医生ID
   * @param {string} firstMessage - 第一条消息内容
   * @returns {Promise<Object>} 聊天房间信息
   */
  async startNewChatWithDoctor(patientId, doctorId, firstMessage) {
    try {
      // 1. 验证聊天权限
      const permission = await this.canPatientChatWithDoctor(patientId, doctorId);
      if (!permission.canChat) {
        throw new Error(`无法发起聊天: ${permission.reason}`);
      }

      // 2. 检查是否已有聊天房间
      const roomId = generateRoomId(patientId, doctorId);
      const existingMessage = await LhxMessage.findOne({ roomId });
      
      if (existingMessage) {
        // 如果已有聊天，直接发送新消息
        const message = await this.sendMessage({
          roomId,
          senderId: patientId,
          senderType: 'patient',
          content: firstMessage,
          messageType: 'text'
        });

        return {
          roomId,
          isNewChat: false,
          message,
          permission
        };
      } else {
        // 创建新聊天房间
        const result = await this.createChatRoom(patientId, doctorId, firstMessage);
        
        return {
          ...result,
          isNewChat: true,
          permission
        };
      }
    } catch (error) {
      console.error('发起新聊天失败:', error);
      throw error;
    }
  }
}

module.exports = new LhxChatService();